namespace ContactsSync.Providers.ViewModels
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Globalization;
    using System.Linq;
    using Infrastructure.Models;
    using Microsoft.Practices.Composite.Events;
    using Microsoft.Practices.Composite.Presentation.Commands;

    public abstract class BaseProviderViewModel : INotifyPropertyChanged
    {
        private IContactsProvider contactsProvider;

        private ObservableCollection<Contact> contacts;

        private bool isLoading;

        protected BaseProviderViewModel(IEventAggregator eventAggregator)
        {
            this.EventAggregator = eventAggregator;
            this.SearchContactCommand = new DelegateCommand<string>(this.SearchContact);
            this.Contacts = new ObservableCollection<Contact>();
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public string ProviderName { get; private set; }

        public DelegateCommand<string> SearchContactCommand { get; private set; }

        public ObservableCollection<Contact> Contacts
        {
            get
            {
                return this.contacts;
            }

            protected set
            {
                this.contacts = value;
                this.OnPropertyChanged("Contacts");
            }
        }

        public bool IsLoading
        {
            get
            {
                return this.isLoading;
            }

            protected set
            {
                this.isLoading = value;
                this.OnPropertyChanged("IsLoading");
            }
        }

        protected IEventAggregator EventAggregator { get; private set; }

        private ObservableCollection<Contact> AvailableContacts { get; set; }

        public void SetProvider(IContactsProvider provider)
        {
            if (provider == null)
            {
                throw new ArgumentNullException("provider");
            }

            this.contactsProvider = provider;
            this.contactsProvider.RetrieveContactsCompleted += this.ContactsProvider_RetrieveContactsCompleted;
            this.ProviderName = this.contactsProvider.ProviderName;
            this.IsLoading = true;
            this.RetrieveContacts();
        }

        protected virtual void RetrieveContacts()
        {
            this.contactsProvider.RetrieveContactsAsync();  
        }

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler changed = this.PropertyChanged;
            if (changed != null)
            {
                changed(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private void SearchContact(string filter)
        {
            IEnumerable<Contact> filteredContacts = this.AvailableContacts.Where(contact => contact
                                        .ToString()
                                        .ToUpper(CultureInfo.InvariantCulture)
                                        .Contains(filter.ToUpper(CultureInfo.InvariantCulture)));

            this.Contacts = new ObservableCollection<Contact>(filteredContacts);
        }

        private void ContactsProvider_RetrieveContactsCompleted(object sender, DataEventArgs<IList<Contact>> e)
        {
            ObservableCollection<Contact> availableContacts = new ObservableCollection<Contact>(e.Value);
            this.AvailableContacts = availableContacts;
            this.Contacts = availableContacts;
            this.IsLoading = false;
        }
    }
}